/**
 * 缓存工具模块
 * 提供多种缓存策略和存储方式，包括内存缓存、本地存储缓存等
 */

/**
 * 内存缓存类
 */
class MemoryCache {
  constructor(options = {}) {
    this.cache = new Map();
    this.timers = new Map();
    this.maxSize = options.maxSize || 100;
    this.defaultTTL = options.defaultTTL || 0; // 0表示永不过期
  }

  /**
   * 设置缓存
   * @param {string} key 键
   * @param {*} value 值
   * @param {number} ttl 过期时间（毫秒），0表示永不过期
   */
  set(key, value, ttl = this.defaultTTL) {
    // 如果超过最大容量，删除最旧的缓存
    if (this.cache.size >= this.maxSize && !this.cache.has(key)) {
      const firstKey = this.cache.keys().next().value;
      this.delete(firstKey);
    }

    // 清除旧的定时器
    if (this.timers.has(key)) {
      clearTimeout(this.timers.get(key));
      this.timers.delete(key);
    }

    // 设置缓存
    this.cache.set(key, {
      value,
      timestamp: Date.now(),
      ttl
    });

    // 设置过期定时器
    if (ttl > 0) {
      const timer = setTimeout(() => {
        this.delete(key);
      }, ttl);
      this.timers.set(key, timer);
    }
  }

  /**
   * 获取缓存
   * @param {string} key 键
   * @returns {*} 值或undefined
   */
  get(key) {
    const item = this.cache.get(key);
    if (!item) {
      return undefined;
    }

    // 检查是否过期
    if (item.ttl > 0 && Date.now() - item.timestamp > item.ttl) {
      this.delete(key);
      return undefined;
    }

    return item.value;
  }

  /**
   * 检查键是否存在
   * @param {string} key 键
   * @returns {boolean} 是否存在
   */
  has(key) {
    return this.get(key) !== undefined;
  }

  /**
   * 删除缓存
   * @param {string} key 键
   * @returns {boolean} 是否删除成功
   */
  delete(key) {
    if (this.timers.has(key)) {
      clearTimeout(this.timers.get(key));
      this.timers.delete(key);
    }
    return this.cache.delete(key);
  }

  /**
   * 清空所有缓存
   */
  clear() {
    // 清除所有定时器
    for (const timer of this.timers.values()) {
      clearTimeout(timer);
    }
    this.timers.clear();
    this.cache.clear();
  }

  /**
   * 获取缓存大小
   * @returns {number} 缓存项数量
   */
  size() {
    return this.cache.size;
  }

  /**
   * 获取所有键
   * @returns {Array<string>} 键数组
   */
  keys() {
    return Array.from(this.cache.keys());
  }

  /**
   * 获取缓存统计信息
   * @returns {Object} 统计信息
   */
  stats() {
    const now = Date.now();
    let expiredCount = 0;
    let totalSize = 0;

    for (const [key, item] of this.cache) {
      if (item.ttl > 0 && now - item.timestamp > item.ttl) {
        expiredCount++;
      }
      totalSize += JSON.stringify(item.value).length;
    }

    return {
      size: this.cache.size,
      maxSize: this.maxSize,
      expiredCount,
      totalSize
    };
  }
}

/**
 * 本地存储缓存类
 */
class LocalStorageCache {
  constructor(options = {}) {
    this.prefix = options.prefix || 'cache_';
    this.defaultTTL = options.defaultTTL || 0;
  }

  /**
   * 生成完整的键名
   * @param {string} key 原始键
   * @returns {string} 完整键名
   */
  _getFullKey(key) {
    return this.prefix + key;
  }

  /**
   * 设置缓存
   * @param {string} key 键
   * @param {*} value 值
   * @param {number} ttl 过期时间（毫秒）
   */
  set(key, value, ttl = this.defaultTTL) {
    try {
      const item = {
        value,
        timestamp: Date.now(),
        ttl
      };
      localStorage.setItem(this._getFullKey(key), JSON.stringify(item));
    } catch (e) {
      console.warn('LocalStorage缓存设置失败:', e);
    }
  }

  /**
   * 获取缓存
   * @param {string} key 键
   * @returns {*} 值或undefined
   */
  get(key) {
    try {
      const fullKey = this._getFullKey(key);
      const itemStr = localStorage.getItem(fullKey);

      if (!itemStr) {
        return undefined;
      }

      const item = JSON.parse(itemStr);

      // 检查是否过期
      if (item.ttl > 0 && Date.now() - item.timestamp > item.ttl) {
        localStorage.removeItem(fullKey);
        return undefined;
      }

      return item.value;
    } catch (e) {
      console.warn('LocalStorage缓存获取失败:', e);
      return undefined;
    }
  }

  /**
   * 检查键是否存在
   * @param {string} key 键
   * @returns {boolean} 是否存在
   */
  has(key) {
    return this.get(key) !== undefined;
  }

  /**
   * 删除缓存
   * @param {string} key 键
   * @returns {boolean} 是否删除成功
   */
  delete(key) {
    try {
      localStorage.removeItem(this._getFullKey(key));
      return true;
    } catch (e) {
      console.warn('LocalStorage缓存删除失败:', e);
      return false;
    }
  }

  /**
   * 清空所有缓存
   */
  clear() {
    try {
      const keys = Object.keys(localStorage);
      for (const key of keys) {
        if (key.startsWith(this.prefix)) {
          localStorage.removeItem(key);
        }
      }
    } catch (e) {
      console.warn('LocalStorage缓存清空失败:', e);
    }
  }

  /**
   * 获取所有键
   * @returns {Array<string>} 键数组
   */
  keys() {
    try {
      const keys = [];
      for (const key of Object.keys(localStorage)) {
        if (key.startsWith(this.prefix)) {
          keys.push(key.substring(this.prefix.length));
        }
      }
      return keys;
    } catch (e) {
      console.warn('LocalStorage缓存键获取失败:', e);
      return [];
    }
  }

  /**
   * 清理过期缓存
   */
  cleanup() {
    try {
      const now = Date.now();
      const keys = Object.keys(localStorage);

      for (const key of keys) {
        if (key.startsWith(this.prefix)) {
          const itemStr = localStorage.getItem(key);
          if (itemStr) {
            try {
              const item = JSON.parse(itemStr);
              if (item.ttl > 0 && now - item.timestamp > item.ttl) {
                localStorage.removeItem(key);
              }
            } catch (e) {
              // 数据格式错误，删除
              localStorage.removeItem(key);
            }
          }
        }
      }
    } catch (e) {
      console.warn('LocalStorage缓存清理失败:', e);
    }
  }
}

/**
 * LRU缓存类（最近最少使用）
 */
class LRUCache {
  constructor(maxSize = 100) {
    this.maxSize = maxSize;
    this.cache = new Map();
  }

  /**
   * 设置缓存
   * @param {string} key 键
   * @param {*} value 值
   */
  set(key, value) {
    if (this.cache.has(key)) {
      // 如果键已存在，删除后重新添加（移到最新位置）
      this.cache.delete(key);
    } else if (this.cache.size >= this.maxSize) {
      // 如果超过容量，删除最旧的项
      const firstKey = this.cache.keys().next().value;
      this.cache.delete(firstKey);
    }

    this.cache.set(key, value);
  }

  /**
   * 获取缓存
   * @param {string} key 键
   * @returns {*} 值或undefined
   */
  get(key) {
    if (this.cache.has(key)) {
      const value = this.cache.get(key);
      // 移到最新位置
      this.cache.delete(key);
      this.cache.set(key, value);
      return value;
    }
    return undefined;
  }

  /**
   * 检查键是否存在
   * @param {string} key 键
   * @returns {boolean} 是否存在
   */
  has(key) {
    return this.cache.has(key);
  }

  /**
   * 删除缓存
   * @param {string} key 键
   * @returns {boolean} 是否删除成功
   */
  delete(key) {
    return this.cache.delete(key);
  }

  /**
   * 清空所有缓存
   */
  clear() {
    this.cache.clear();
  }

  /**
   * 获取缓存大小
   * @returns {number} 缓存项数量
   */
  size() {
    return this.cache.size;
  }

  /**
   * 获取所有键
   * @returns {Array<string>} 键数组
   */
  keys() {
    return Array.from(this.cache.keys());
  }
}

// 创建默认缓存实例
const defaultMemoryCache = new MemoryCache();
const defaultLocalStorageCache = new LocalStorageCache();
const defaultLRUCache = new LRUCache();

/**
 * 设置内存缓存
 * @param {string} key 键
 * @param {*} value 值
 * @param {number} ttl 过期时间（毫秒）
 */
export function setMemoryCache(key, value, ttl) {
  defaultMemoryCache.set(key, value, ttl);
}

/**
 * 获取内存缓存
 * @param {string} key 键
 * @returns {*} 值或undefined
 */
export function getMemoryCache(key) {
  return defaultMemoryCache.get(key);
}

/**
 * 删除内存缓存
 * @param {string} key 键
 * @returns {boolean} 是否删除成功
 */
export function deleteMemoryCache(key) {
  return defaultMemoryCache.delete(key);
}

/**
 * 清空内存缓存
 */
export function clearMemoryCache() {
  defaultMemoryCache.clear();
}

/**
 * 设置本地存储缓存
 * @param {string} key 键
 * @param {*} value 值
 * @param {number} ttl 过期时间（毫秒）
 */
export function setLocalCache(key, value, ttl) {
  defaultLocalStorageCache.set(key, value, ttl);
}

/**
 * 获取本地存储缓存
 * @param {string} key 键
 * @returns {*} 值或undefined
 */
export function getLocalCache(key) {
  return defaultLocalStorageCache.get(key);
}

/**
 * 删除本地存储缓存
 * @param {string} key 键
 * @returns {boolean} 是否删除成功
 */
export function deleteLocalCache(key) {
  return defaultLocalStorageCache.delete(key);
}

/**
 * 清空本地存储缓存
 */
export function clearLocalCache() {
  defaultLocalStorageCache.clear();
}

/**
 * 设置LRU缓存
 * @param {string} key 键
 * @param {*} value 值
 */
export function setLRUCache(key, value) {
  defaultLRUCache.set(key, value);
}

/**
 * 获取LRU缓存
 * @param {string} key 键
 * @returns {*} 值或undefined
 */
export function getLRUCache(key) {
  return defaultLRUCache.get(key);
}

/**
 * 删除LRU缓存
 * @param {string} key 键
 * @returns {boolean} 是否删除成功
 */
export function deleteLRUCache(key) {
  return defaultLRUCache.delete(key);
}

/**
 * 清空LRU缓存
 */
export function clearLRUCache() {
  defaultLRUCache.clear();
}

/**
 * 缓存装饰器函数
 * @param {Function} fn 要缓存的函数
 * @param {Object} options 选项
 * @param {string} options.type 缓存类型：'memory', 'local', 'lru'
 * @param {number} options.ttl 过期时间（毫秒）
 * @param {Function} options.keyGenerator 键生成器函数
 * @returns {Function} 装饰后的函数
 */
export function memoize(fn, options = {}) {
  const {
    type = 'memory',
    ttl = 0,
    resolver = null  // 自定义键生成器，接收所有参数
  } = options;

  const cache = type === 'local' ? defaultLocalStorageCache :
                type === 'lru' ? defaultLRUCache :
                defaultMemoryCache;

  // 使用独立的Map存储函数结果，避免JSON.stringify的问题
  const resultCache = new Map();

  // 默认的键生成逻辑：使用参数长度+类型来生成简单键
  const defaultResolver = (...args) => {
    if (args.length === 0) return '__no_args__';
    if (args.length === 1 && (typeof args[0] === 'string' || typeof args[0] === 'number')) {
      return String(args[0]);
    }
    // 对于复杂参数，尝试JSON.stringify，失败则使用参数特征
    try {
      return JSON.stringify(args);
    } catch (e) {
      // 处理循环引用等情况
      return args.map((arg, i) => `${i}:${typeof arg}`).join('|');
    }
  };

  const keyGen = resolver || defaultResolver;

  return function(...args) {
    const key = keyGen.apply(this, args);

    // 优先从Map缓存中查找（避免undefined检查问题）
    if (resultCache.has(key)) {
      return resultCache.get(key);
    }

    // 执行函数获取结果
    const result = fn.apply(this, args);

    // 同时存储到Map和指定缓存中
    resultCache.set(key, result);

    if (type === 'lru') {
      cache.set(key, result);
    } else {
      cache.set(key, result, ttl);
    }

    return result;
  };
}

/**
 * 创建新的缓存实例
 * @param {string} type 缓存类型：'memory', 'local', 'lru'
 * @param {Object} options 选项
 * @returns {Object} 缓存实例
 */
export function createCache(type = 'memory', options = {}) {
  switch (type) {
    case 'memory':
      return new MemoryCache(options);
    case 'local':
      return new LocalStorageCache(options);
    case 'lru':
      return new LRUCache(options.maxSize);
    default:
      throw new Error('不支持的缓存类型');
  }
}

// 导出缓存类
export { MemoryCache, LocalStorageCache, LRUCache };